using namespace std;
#include <map>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <signal.h>
#include <openssl/md5.h>
#include <arpa/inet.h>
#include <pthread.h>  
#include <list>
#include <set>
#include <vector>

#define STRQ 0xAC
#define STRS 0xAB
#define KPAV 0xF8
#define HLLO 0xFA
#define JNRQ 0xFC
#define JNRS 0xFB
#define NTFY 0xF7
#define CKRS 0xF5
#define CKRQ 0xF6

typedef struct beaconsMap
{
	char hostName[512];
	int port;
} beacon;

union Values 
{
	char asChar;
	unsigned char asUChar;
	short asShort;
	unsigned short asUShort;
	int asInt;
	unsigned int asUInt;
	long asLong;
	unsigned long asULong;	
	float asFloat;
	double asDouble;
	char asStr[512];
	Values() { asULong = 0; }
	Values(char in) { asUChar = in; }
	Values(unsigned char in) { asChar = in; }
	Values(short in) { asShort = in; }
	Values(unsigned short in) { asUShort = in; }
	Values(int in) { asInt = in; }
	Values(unsigned int in) { asUInt = in; }
	Values(long in) { asLong = in; }
	Values(unsigned long in) { asULong = in; }
	Values(float in) { asFloat = in; }
	Values(double in) { asDouble = in; }
	Values(char* in) { strcpy(asStr,in); }
	
	
	operator char() { return asChar; }
	operator unsigned char() { return asUChar; }
	operator short() { return asShort; }
	operator unsigned short() { return asUShort; }
	operator int() { return asInt; }
	operator unsigned int() { return asUInt; }
	operator long() { return asLong; }
	operator unsigned long() { return asULong; }
	operator float() { return asFloat; }
	operator double() { return asDouble; }
	operator char*() { return asStr; }
};

typedef struct beaconmap
{
	int socknumber;
	int connectflag;
	int nodeIndex;
}beaconmap; 

typedef struct msg_header
{
	uint8_t msgtype;
	char uoid[20];
	uint8_t timetolive;
	uint8_t reserved;
	uint32_t datalength;
}msg_header;
 
typedef struct join_msg
{
	uint32_t hostlocation;
	uint16_t hostport;
	char hostname[512];
}join_msg;

typedef struct join_response_msg
{
	char uoid[20];
	uint32_t distance;
	uint16_t hostport;
	char hostname[512];
}join_response_msg;

typedef struct hello_msg
{
	msg_header header;
	uint16_t hostport;
	char hostname[512];
}hello_msg;

typedef struct status_msg
{
	uint8_t statustype;
}status_msg;

typedef struct status_response_msg
{
	char uoid[20];
	uint16_t hostinfolength;
	uint16_t hostport;
	char hostname[512];
	char data[512];
}status_response_msg;

typedef struct listBuffStruct
{
char listBuff[512];
uint32_t datalength;
int portNumber;
int logtype;
}listBuffStruct;

typedef struct writeStruct
{
	int portNumber;
	int sock;
}writeStruct;

typedef struct writeListData
{
	list<listBuffStruct> response;
	char hostname[512];
	bool dieflag;
}writeListData;

typedef struct allTimers
{
double keepAliveTime;
double joinTime;
}allTimers;

typedef struct uoidStr
{
double timeOfTheDay;
double msgLifeTime;
char msgUOID[20];
}uoidStr;

typedef struct neighborStruct
{
	uint16_t port;
	char hostname[512];
}neighborStruct;

typedef struct statusSTR
{
char uoid[20];
}statusSTR;

typedef struct fromUOIDStr
{
char uoid[20];
int portnumber;
}fromUOIDStr;

extern multimap<int,neighborStruct> neighborMap;
extern multimap<int, neighborStruct>::iterator itNeighborMap;
extern double globalStatusTime;
extern double checkResponseTime;
extern int joinCount;

extern list<uoidStr> myUOIDList;
extern list<fromUOIDStr> myFromUOIDList;
extern map<int,allTimers> myTimers;
extern map<int,beaconmap> myMap;
extern unsigned int port_recieve;
extern unsigned int port_timetolive;
extern char port_recieve_str[512];
extern char statusFile[128];
extern char hostname[512];
extern char node_id[512];
extern char node_instance_id[512];
extern bool notifyFlag;
extern hello_msg myHello;
extern pthread_mutex_t maplock;
extern pthread_mutex_t timerlock;
extern pthread_mutex_t uoidlock;
extern pthread_mutex_t loglock;

extern int nodeIndex;
extern map<string, Values> initMap;
extern bool isBeacon;
extern bool resetFlag;
extern bool joinFlag;
extern list<beacon> allNeighbors;
extern list<beacon>::iterator itAllNeighbors;

extern multimap<int, int> statusResp;
extern list<listBuffStruct> eventQueue;
extern pthread_mutex_t eventQueueMutex;

extern map<int, writeListData> writeMap;
extern pthread_mutex_t writeMapMutex;

extern bool dieChild;
extern bool serverShutdown;
extern list<statusSTR> statusResponseList;
extern map<int, bool> joinRequestMap;
extern char input_line[512];
extern pthread_mutex_t statusRespLock;

extern pthread_t acceptThread;
extern pthread_t sig_thr_id;
extern pthread_t eventDisp;
extern pthread_t keepAliveThread;
extern pthread_t commandLine;
extern pthread_t timerThr;
extern pthread_mutex_t notifyLock;
extern int notifyCount;
extern bool checkFlag;
extern int globalAcceptSock;

extern int minNeighCount;
extern bool minNeighFlag;

extern int printFlag;
extern int signalIntFlag;

void *connect_f(void *ptr);
void *eventDispatcher(void *ptr);
void *accept_f(void *ptr);
void *terminalCommands(void *ptr);
void *timerSetThread(void *ptr);
void *keepAlive(void *arg);
void *connect_f(void *ptr);
void *accept_f(void *ptr);
void *writefun(void *ptr);
void *readfun(void *ptr);

void remAllWhiteSpaces(char *str);
void parser_function(int argc, char *argv[]);
char *GetUOID( char *node_inst_id, char *obj_type, char *uoid_buf, int uoid_buf_sz);
void createMsgHdrStr(msg_header *msg, uint8_t msgtype,uint8_t timetolive,char* msgtypestr,char* node_inst_id,uint32_t msgsize);
void write_to_log(listBuffStruct lbtemp, int logtype,struct timeval);
int findInUOIDList(char* msgUOID);
void fillMsgHdrStructure(msg_header &hdr, char* buf);
void fillMsgHdrBuffer(msg_header &hdr, char*  buf);
void statusProcessing(msg_header msgRespHdr, listBuffStruct eventReq);
void joinProcessing(msg_header msgRespHdr, listBuffStruct eventReq);
void notifyProcessing(msg_header msgRespHdr, listBuffStruct eventReq);
void parserInitNeighFile();
void init();
int restartMain(int argc, char* argv[]);
